﻿using System;
using System.Collections.Generic;
using System.Data.Objects;
using System.Linq;
using System.Text;
using Fintech.Utils.Diagnostics;

namespace ZOVNP.Engine
{
    /// <summary> Итератор, порождающий доменные объекты и поддерживающий синхронизацию потоков. </summary>
    /// <typeparam name="T"> Тип порождаемых объектов. </typeparam>
    /// <remarks>
    /// Как только итератор достигает окончания коллекции или же уничтожается вызовом метода <c>Dispose()</c>, то снимается блокировка на создание объектов типа <c>DataReader</c>.
    /// </remarks>
    internal class ObjectResultEnumerator<T> : IEnumerator<T>
    {
        #region Поля

        private IEnumerator<T> enumerator;
        private ObjectResult result;
        private bool lockReleased;
        private Action releaseAction;

        #endregion

        #region Конструкторы

        /// <summary> Создать синхронизирующий итератор. </summary>
        /// <param name="Enumerator"> Оборачиваемый итератор. </param>
        /// <param name="ReleaseAction"> Делегат снятия блокировки. </param>
        /// <remarks>
        /// Делегат передаётся, чтобы не передавать generic-параметр типа SkifObjectQuery, что приведёт к добавлению 
        /// ещё одного шаблонного параметра в декларацию класса итератора.
        /// </remarks>
        public ObjectResultEnumerator(ObjectResult Result, IEnumerator<T> Enumerator, Action ReleaseAction)
        {
            result = Result;
            enumerator = Enumerator;
            releaseAction = ReleaseAction;
        }

        #endregion

        #region Свойства

        /// <summary> Текущий элемент итератора. </summary>
        public T Current { get { return enumerator.Current; } }

        /// <summary> Текущий элемент итератора. </summary>
        object System.Collections.IEnumerator.Current { get { return Current; } }

        #endregion

        #region Методы

        /// <summary> Снятие блокировки через делегат. </summary>
        private void ReleaseLock()
        {
            if (lockReleased) return;
            lockReleased = true;
            if (releaseAction != null)
                releaseAction();
        }

        /// <summary> Уничтожить ресурсы итератора. </summary>
        /// <remarks> Происходит снятие блокировки. </remarks>
        public void Dispose()
        {
            enumerator.Dispose();
            result.Dispose();
            ReleaseLock();
        }

        /// <summary> Переместить итератор на одну позицию вперёд. </summary>
        /// <returns> True, если итератор смог сделать шаг, иначе false. </returns>
        public bool MoveNext()
        {
            var result = enumerator.MoveNext();
            if (!result) ReleaseLock();
            else if (object.ReferenceEquals(Current, null) && !typeof(T).IsValueType) // странная ситуация, когда итератор по каким-то причинам не смог материализовать объект и при этом не выдал никакого исключения
                DebugTuner.Instance.Break(DebuggerLevel.Error); // bug с Include(): если сюда попало управление, то обращаться к Ивану Максимову 
            return result;
        }

        /// <summary> Сбросить итератор в начальное положение. </summary>
        /// <remarks> Нижележащий итератор, скорее всего, сгенерирует исключение <c>NotSupportedException</c>. </remarks>
        public void Reset() { enumerator.Reset(); }

        #endregion
    }
}
